Bug 631599 - Allow to use arbitrary surfaces for offscreen windows
authorMichael Natterer <mitch@gimp.org>
Thu, 14 Oct 2010 11:25:23 +0000 (13:25 +0200)
committerMichael Natterer <mitch@gimp.org>
Thu, 14 Oct 2010 11:25:23 +0000 (13:25 +0200)
Add signal GdkWindow::create-surface which allows to use any
surface type as storage for offscreen windows.

Test the new signal in tests/gdkoffscreenbox.c

gdk/gdkinternals.h
gdk/gdkmarshalers.list
gdk/gdkoffscreenwindow.c
gdk/gdkwindow.c
gdk/gdkwindow.h
tests/gtkoffscreenbox.c

index e2f45d5cf5713b4e08e7fedf5f54ad3b64cb8123..e1b458e8038f4a240f0e5571024ce9313063a376 100644 (file)
@@ -550,6 +550,9 @@ GType gdk_offscreen_window_get_type (void);
 void       _gdk_offscreen_window_new                 (GdkWindow     *window,
                                                      GdkWindowAttr *attributes,
                                                      gint           attributes_mask);
+cairo_surface_t * _gdk_offscreen_window_create_surface (GdkWindow *window,
+                                                        gint       width,
+                                                        gint       height);
 
 
 /************************************
index ea36baeb8894189a1b08f0b045902a9c2a148747..cb42499721f66a87274a10cf721dfe8f7b823433 100644 (file)
@@ -3,4 +3,5 @@ VOID:BOOLEAN
 VOID:POINTER,POINTER,POINTER
 OBJECT:VOID
 OBJECT:DOUBLE,DOUBLE
+BOXED:INT,INT
 VOID:DOUBLE,DOUBLE,POINTER,POINTER
index 0cea577379e20e3aaaa832094498685f851ef2bd..55d1fad827157cca082509c9e34a3288090b3f5f 100644 (file)
@@ -113,17 +113,11 @@ get_surface (GdkOffscreenWindow *offscreen)
   if (! offscreen->surface)
     {
       GdkWindowObject *private = (GdkWindowObject *) offscreen->wrapper;
-      cairo_surface_t *similar;
 
-      similar = _gdk_drawable_ref_cairo_surface ((GdkWindow *)private->parent);
-
-      offscreen->surface = cairo_surface_create_similar (similar,
-                                                         /* FIXME: use visual */
-                                                         CAIRO_CONTENT_COLOR,
-                                                         private->width,
-                                                         private->height);
-
-      cairo_surface_destroy (similar);
+      g_signal_emit_by_name (private, "create-surface",
+                             private->width,
+                             private->height,
+                             &offscreen->surface);
     }
 
   return offscreen->surface;
@@ -155,6 +149,30 @@ gdk_offscreen_window_ref_cairo_surface (GdkDrawable *drawable)
   return cairo_surface_reference (get_surface (offscreen));
 }
 
+cairo_surface_t *
+_gdk_offscreen_window_create_surface (GdkWindow *offscreen,
+                                      gint       width,
+                                      gint       height)
+{
+  GdkWindowObject *private = (GdkWindowObject *) offscreen;
+  cairo_surface_t *similar;
+  cairo_surface_t *surface;
+
+  g_return_val_if_fail (GDK_IS_OFFSCREEN_WINDOW (private->impl), NULL);
+
+  similar = _gdk_drawable_ref_cairo_surface ((GdkWindow *)private->parent);
+
+  surface = cairo_surface_create_similar (similar,
+                                          /* FIXME: use visual */
+                                          CAIRO_CONTENT_COLOR,
+                                          width,
+                                          height);
+
+  cairo_surface_destroy (similar);
+
+  return surface;
+}
+
 void
 _gdk_offscreen_window_new (GdkWindow     *window,
                           GdkWindowAttr *attributes,
index 6801900f8acc09141813217187225e6041264a3f..8be5dcc21327126febb57ee9a1339d08cd8f30d2 100644 (file)
@@ -27,6 +27,8 @@
 
 #include "config.h"
 
+#include <cairo-gobject.h>
+
 #include "gdkwindow.h"
 
 #ifdef GDK_WINDOWING_X11
@@ -185,6 +187,7 @@ enum {
   PICK_EMBEDDED_CHILD, /* only called if children are embedded */
   TO_EMBEDDER,
   FROM_EMBEDDER,
+  CREATE_SURFACE,
   LAST_SIGNAL
 };
 
@@ -353,6 +356,18 @@ accumulate_get_window (GSignalInvocationHint *ihint,
   return g_value_get_object (handler_return) == NULL;
 }
 
+static gboolean
+create_surface_accumulator (GSignalInvocationHint *ihint,
+                            GValue                *return_accu,
+                            const GValue          *handler_return,
+                            gpointer               data)
+{
+  g_value_copy (handler_return, return_accu);
+
+  /* Stop on the first non-NULL return value */
+  return g_value_get_boxed (handler_return) == NULL;
+}
+
 static GQuark quark_pointer_window = 0;
 
 static void
@@ -373,6 +388,8 @@ gdk_window_class_init (GdkWindowObjectClass *klass)
   drawable_class->get_clip_region = gdk_window_get_clip_region;
   drawable_class->get_visible_region = gdk_window_get_visible_region;
 
+  klass->create_surface = _gdk_offscreen_window_create_surface;
+
   quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window");
 
 
@@ -476,6 +493,39 @@ gdk_window_class_init (GdkWindowObjectClass *klass)
                  G_TYPE_DOUBLE,
                  G_TYPE_POINTER,
                  G_TYPE_POINTER);
+
+  /**
+   * GdkWindow::create-surface:
+   * @window: the offscreen window on which the signal is emitted
+   * @width: the width of the offscreen surface to create
+   * @height: the height of the offscreen surface to create
+   *
+   * The ::create-surface signal is emitted when an offscreen window
+   * needs its surface (re)created, which happens either when the the
+   * window is first drawn to, or when the window is being
+   * resized. The first signal handler that returns a non-%NULL
+   * surface will stop any further signal emission, and its surface
+   * will be used.
+   *
+   * Note that it is not possible to access the window's previous
+   * surface from within any callback of this signal. Calling
+   * gdk_offscreen_window_get_surface() will lead to a crash.
+   *
+   * Returns: the newly created #cairo_surface_t for the offscreen window
+   *
+   * Since: 3.0
+   */
+  signals[CREATE_SURFACE] =
+    g_signal_new (g_intern_static_string ("create-surface"),
+                  G_OBJECT_CLASS_TYPE (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GdkWindowObjectClass, create_surface),
+                  create_surface_accumulator, NULL,
+                  _gdk_marshal_BOXED__INT_INT,
+                  CAIRO_GOBJECT_TYPE_SURFACE,
+                  2,
+                  G_TYPE_INT,
+                  G_TYPE_INT);
 }
 
 static void
index 5f2c6cbbc3cc22bc07fbd5899e9a0c7846763b00..05a998930ed624d9997ec41982f042f539ce9133 100644 (file)
@@ -489,6 +489,10 @@ typedef struct _GdkWindowObjectClass GdkWindowObjectClass;
 struct _GdkWindowObjectClass
 {
   GdkDrawableClass parent_class;
+
+  cairo_surface_t * (* create_surface) (GdkWindow *window,
+                                        gint       width,
+                                        gint       height);
 };
 
 /* Windows
index fe84db210950f3cb62e2611f2faeb02b8269d6dc..1c19fd996e4ba622d1d90db427d149f045398a33 100644 (file)
@@ -234,6 +234,14 @@ offscreen_window_from_parent2 (GdkWindow       *window,
              offscreen_x, offscreen_y);
 }
 
+static cairo_surface_t *
+gdk_offscreen_box_create_alpha_image_surface (GdkWindow *offscreen,
+                                              gint       width,
+                                              gint       height)
+{
+  return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+}
+
 static void
 gtk_offscreen_box_realize (GtkWidget *widget)
 {
@@ -323,6 +331,10 @@ gtk_offscreen_box_realize (GtkWidget *widget)
     gtk_widget_set_parent_window (offscreen_box->child2, offscreen_box->offscreen_window2);
   gdk_offscreen_window_set_embedder (offscreen_box->offscreen_window2,
                                     window);
+
+  g_signal_connect (offscreen_box->offscreen_window2, "create-surface",
+                    G_CALLBACK (gdk_offscreen_box_create_alpha_image_surface),
+                    offscreen_box);
   g_signal_connect (offscreen_box->offscreen_window2, "to-embedder",
                    G_CALLBACK (offscreen_window_to_parent2), offscreen_box);
   g_signal_connect (offscreen_box->offscreen_window2, "from-embedder",